import math
from math import degrees, radians

import random
from random import choice

import pyglet
from pyglet.gl import  *
from pyglet.window import key

import cocos
from cocos.actions import *
from cocos.layer import *
from cocos.scene import *
from cocos.director import director
from cocos.scenes.transitions import *
from cocos.sprite import Sprite
from cocos.particle import *
from cocos.particle_systems import *

import Box2D as box2d

import vec2util
import weapon
import entity
from res import Images
from globalvars import *


#-----------------------
#
#  PlayerBox
#
#-----------------------

class PlayerBox(entity.Entity):
    def __init__(self, world, image=Images.box,*args, **kwargs):
        "Init and keys"
        entity.Entity.__init__(self, world, image, *args, **kwargs)
        self.stateMachine.currentState = self.StillAlive(self)
        self.keys = key.KeyStateHandler()
        director.window.push_handlers(self.keys)
        "HP - hit points"
        self.hp = 100
        
        "Vector"
        self.velocityVec = box2d.b2Vec2(0,0) # connected to analog stick
        self.weaponVec = box2d.b2Vec2(0,0)
        self.weaponNorm = box2d.b2Vec2(0,0)
        self.weaponAngle = 0
        
        "BodyDef"
        self.bodyDef = box2d.b2BodyDef()
        self.bodyDef.linearDamping = 1
        self.bodyDef.angularDamping = 0.6
        
        "Box ShapeDef"
        self.boxShapeDef = box2d.b2PolygonDef()
        self.boxShapeDef.SetAsBox(
                          self.width/RATIO/2.0, 
                         self.height/RATIO/2.0, 
                         (0,0), 0)
        self.boxShapeDef.density = 1.0
        self.boxShapeDef.friction = 0.3
        self.boxShapeDef.restitution = 0.6
        self.boxShapeDef.SetUserData(self)
        
        self.weaponJointDef = box2d.b2RevoluteJointDef()
        self.weaponJointDef.maxMotorTorque= 1.0 ** 10000
        self.weaponJointDef.motorSpeed    = 0.0
        self.weaponJointDef.enableLimit = False
        self.weaponJointDef.enableMotor = True
        self.weaponJoint = None

        "Create the body and the shape(s)"
        self.body = self.world.CreateBody(self.bodyDef)
        self.body.SetBullet(True)
        self.boxShape = self.body.CreateShape(self.boxShapeDef)
        self.body.SetMassFromShapes()

        self.moveSpeed = 100.0*0.001

        "Weapons"
        self.activeWeapon = None
        self.weapons = {}
        self.isSwitchingWeapon = False
        self.isDroppingWeapon = False
        self.crossHair = self.CrossHair(self.world,self)
        
    def update(self,dt):
        "update"
        self.stateMachine.update(dt)
        
    def updateWeaponNorm(self,dt=0):
        "Update weapon normal"
        normTuple = vec2util.normalize(self.weaponVec.tuple())
        self.weaponNorm = -box2d.b2Vec2(normTuple[0],normTuple[1]) 
        return self.weaponNorm
        
    def updateWeaponPosAngle(self,dt):
        "Update the WeaponPos"
        if self.activeWeapon:
            self.activeWeapon.ammoVec = self.updateWeaponNorm(dt)
            self.activeWeapon.body.position = self.body.position + (self.activeWeapon.ammoVec * self.activeWeapon.margin)
            self.activeWeapon.body.angle = self.weaponAngle

        
    def setActiveWeapon(self,w):
        "Use one of the available weapons"
        if self.activeWeapon:
            prev = self.activeWeapon
            prev.stateMachine.changeState(prev.AsInactiveWeapon(prev))
            
        if w == None:
            self.activeWeapon == None
            return
        elif type(w) == int:
            self.activeWeapon = self.weapons[w]
        else:
            self.activeWeapon = [k for k, v in self.weapons.iteritems() if v == w][0]
        
        self.activeWeapon.stateMachine.changeState(self.activeWeapon.AsActiveWeapon(self.activeWeapon))
        

    def switchWeapon(self,dt):
        "Change active weapon to other available ones"
        if self.keys[key.Q] or self.keys[key.E]:
            if len(self.weapons) > 1:
                if not self.isSwitchingWeapon:
                    self.isSwitchingWeapon = True
                    currentWeapon = self.activeWeapon
                    while self.activeWeapon == currentWeapon:
                        self.setActiveWeapon(random.choice(self.weapons.keys()))
        else:
            self.isSwitchingWeapon = False
                
            
    def dropWeapon(self,dt):
        "Drop current weapon"
        if self.keys[key.BACKSLASH]:
            if not self.isDroppingWeapon:
                if self.activeWeapon:
                    self.isDroppingWeapon = True
                    self.activeWeapon.stateMachine.changeState(self.activeWeapon.Dropped(self.activeWeapon))
                    del self.weapons[self.activeWeapon.id]
                    self.activeWeapon = None
                    if self.weapons != {}:
                        self.setActiveWeapon(random.choice(self.weapons.keys()))
                    else:
                        self.setActiveWeapon(None)
        else:
            self.isDroppingWeapon = False
            
                
    def throwWeapon(self,dt=0):
        "Throw current weapon to something else"
        pass
    
    def addWeapon(self,w):
        "Add a weapon"
        w.ownedTo(self)
        self.weapons[w.id] = w
        self.setActiveWeapon(w.id)
        
            
    def removeWeapon(self,name):
        "Remove available weapon"    
        pass
        
    def onTriggerWeapon(self,dt):
        "Triggered"
        if self.activeWeapon:
            self.activeWeapon.onTrigger(dt)
    
    def offTriggerWeapon(self,dt):
        "Relased Trigger"
        if self.activeWeapon:
            self.activeWeapon.offTrigger(dt)
        
    def isBumpedSomething(self):
        "Hit something"
        shape_pairs = [(p.shape1, p.shape2) for p in self.world.points]
        for shape1, shape2 in shape_pairs:
            entity1 = shape1.GetUserData()
            entity2 = shape2.GetUserData()
            if entity1 == self: return entity2
            elif entity2 == self:return entity1
        return None

    def move(self,dt=0):
        "Mooove"
        self.body.WakeUp()
        #self.body.ApplyImpulse((-self.velocityVec * self.moveSpeed), self.body.position)
        
        if self.keys[key.W]:
            self.velocityVec = -box2d.b2Vec2(0,46)
        if self.keys[key.A]:
            self.velocityVec = -box2d.b2Vec2(-46,0)
        if self.keys[key.S]:
            self.velocityVec = -box2d.b2Vec2(0,-46)
        if self.keys[key.D]:
            self.velocityVec = -box2d.b2Vec2(46,0)
        
        if self.keys[key.W] and self.keys[key.D]:
            self.velocityVec = -box2d.b2Vec2(33,33)
        if self.keys[key.D] and self.keys[key.S]:
            self.velocityVec = -box2d.b2Vec2(33,-33)
        if self.keys[key.S] and self.keys[key.A]:
            self.velocityVec = -box2d.b2Vec2(-33,-33)
        if self.keys[key.A] and self.keys[key.W]:
            self.velocityVec = -box2d.b2Vec2(-33,33)
        if (not self.keys[key.A] and not self.keys[key.W] and not self.keys[key.S] and not self.keys[key.D]):
            self.velocityVec = box2d.b2Vec2(0,0)
        
        self.body.ApplyImpulse((-self.velocityVec * self.moveSpeed), self.body.position)
        #self.velocityVec = box2d.b2Vec2(0,0)

    class CrossHair(entity.Entity):
        def __init__(self, world, box, image=Images.crosshair, *args, **kwargs):
            "setup sprite, keys"
            super(PlayerBox.CrossHair,self).__init__(world, image, *args, **kwargs)
            self.world = world
            self.box = box
            self.margin = 10
            self.scale = 1
            
        def update(self,dt):
            "Updates pos, angle, etc when self.box.activeWeapon"
            if self.box.activeWeapon:
                self.visible = True
                self.color = self.box.activeWeapon.color
                self.position = ((self.box.body.position + (self.box.weaponNorm * self.margin)) * RATIO).tuple()
                self.rotation = -degrees(self.box.weaponAngle)
            else:
                self.visible = False
     
    class StillAlive(entity.State):
        "I'm alive!"
        def Enter(self,dt):
            pass
        
        def Execute(self,dt):
            "Things a PlayerBox do when still alive"
            self.ent.move(dt)
            self.ent.updateWeaponPosAngle(dt)
            self.ent.switchWeapon(dt)
            self.ent.dropWeapon(dt)
            self.ent.throwWeapon(dt)
            #print self.ent.weapons
            
            "Collision detections"
            bumped = self.ent.isBumpedSomething()
            if issubclass(type(bumped), weapon.Weapon):
                if isinstance(bumped.stateMachine.currentState, bumped.FreeForAnyone):
                    self.ent.addWeapon(bumped)
                
            if self.ent.keys[key.BACKSPACE]:
                self.ent.hp -=10

            "Update the sprite pos and rot based on its b2Body"
            self.ent.position = (self.ent.body.position * RATIO).tuple()
            self.ent.rotation = -(degrees(self.ent.body.angle))
        
        def Exit(self,dt):
            pass
   
#-----------------------
#
#
#-----------------------
        

        
